#!/usr/bin/env python
# coding=utf-8
import argparse
import signal
import sys
import time
import json
import traceback

from common.log import init, info, warn, debug, error
from common.rabbitmq_interface import RabbitmqService, pika
from common.utils import byteify
from common.aliyun_product_operation_interface import ALiYunRdsOperation
from common.setting import Cmop2ParametersAdapter, ConfigureDiscovery

ALIYUN_SERVER_LOG = "aliyun_rds.log"
ALIYUN_SERVER_CONF = "service.conf"
COMPUTE_EXCHANGE = "vulcanus-iaas-computer"
LOG_EXCHANGE = "vulcanus-iaas-log"
TASK_ROUTE_KEY = "vulcanus.task.create"

# parameters of route key
## 实例管理
create_rds = "vulcanus.rds.dbinstance.create"
delete_rds = "vulcanus.rds.dbinstance.delete"
restart_rds = "vulcanus.rds.dbinstance.reboot"
describe_rds_attr = ""
describe_rdses = ""
modify_rds_spec = "vulcanus.rds.dbinstance.modifyspec"
modify_rds_pay_type = "vulcanus.rds.dbinstance.modifypay"
modify_rds_auto_renew = "vulcanus.rds.dbinstance.modifyautorenewal"
allocate_rds_pub_conn = "vulcanus.rds.netinfo.public.create"
release_rds_pub_conn = "vulcanus.rds.netinfo.public.delete"
# 申请内网连接串（原内外网切换）
switch_rds_net_type = "vulcanus.rds.netinfo.private.create"
describe_rds_net_info = ""
# 修改连接串备注
modify_rds_conn_str = "vulcanus.rds.netinfo.modify"
# 修改RDS实例访问模式
modify_rds_conn_mode = "vulcanus.rds.dbinstance.modifyconnectionmode"
# 修改RDS实例网络类型
modify_rds_net_type = ""
describe_rds_white_ips = ""
modify_rds_white_ips = "vulcanus.rds.iparray.modify"
describe_rds_regions = ""
describe_rds_ha_conf = ""
# 迁移RDS实例可用区
migrate_rds_to_oth_zone = "vulcanus.rds.dbinstance.modifyzone"
# 清理RDS实例日志
purge_rds_log = "vulcanus.rds.dbinstance.purgelog"
# 升级RDS实例版本
upgrade_rds_engine_ver = "vulcanus.rds.dbinstance.modifyversion"
modify_rds_description = "vulcanus.rds.dbinstance.modifydescription"
modify_rds_maintain_time = "vulcanus.rds.dbinstance.modifymaintaintime"
modify_rds_ha_conf = "vulcanus.rds.dbinstance.modifyconfig"
# 切换RDS实例的主备
switch_rds_ha = ""
# 创建RDS只读实例
create_ro_rds = ""
describe_rds_ssl = ""
modify_rds_ssl = ""
describe_rds_tde = ""
modify_rds_tde = ""
# 修改连接地址过期时间
modify_rds_net_expire_time = ""

## 读写分离
allocate_rds_rw_pub_conn = ""
# 查询系统权重分配值
calculate_rds_weight = ""
# 修改读写分离基本信息
modify_rds_rw_attribute = ""
release_rds_rw_pub_coon = ""

## 数据库管理
create_db = "vulcanus.rds.database.create"
delete_db = "vulcanus.rds.database.delete"
describe_db = ""
modify_db = "vulcanus.rds.database.modify"

## 帐号管理
create_account = "vulcanus.rds.account.create"
delete_account = "vulcanus.rds.account.delete"
describe_account = ""
grant_account_privilege = ""
revoke_account_privilege = ""
modify_account_description = "vulcanus.rds.account.modify"
reset_account_password = "vulcanus.rds.account.resetpassword"
reset_account = "vulcanus.rds.account.reset"

## 日志管理
describe_slow_logs = ""
describe_slow_log_rec = ""
describe_err_logs = ""
describe_bin_log_files = ""
describe_sql_collector_policy = ""
describe_sql_log_rec = ""
describe_sql_log_files = ""

## 备份恢复
create_backup = ""
clone_rds = ""
describe_backup = ""
create_tmp_rds = ""
describe_backup_policy = ""
modify_backup_policy = ""
restore_rds = ""
delete_backup = ""

## 监控管理
describe_resource_usage = ""
describe_rds_performance = ""
describe_rds_monitor = ""
modify_rds_monitor = ""

## 参数管理
describe_param_templates = ""
describe_param = ""
modify_param = ""

## 数据迁移
create_upload_path_for_sql_serv = ""
describe_files_for_sql_serv = ""
describe_imports_for_sql_serv = ""
import_db_from_oth_rds = ""
cancel_import = ""

## 性能优化
describe_sql_log_reports = ""
describe_op_advice_on_miss_inx = ""

def _signal_handler(signum, frame):

    info("System exit.")
    sys.exit(0)

def task_report(req, repo, route_key):

    task_rep = {}
    rs = RabbitmqService()
    task_rep["taskCode"] = repo["taskCode"]
    task_rep["action"] = route_key
    task_rep["username"] = repo["username"]
    task_rep["status"] = repo["statusCode"]
    task_rep["requestData"] = req
    task_rep["responseData"] = json.dumps(repo)
    if isinstance(repo["infos"]["requestId"], list):
        for request_id in repo["infos"]["requestId"]:
            task_rep["requestId"] = request_id
            tr_body = json.dumps(task_rep)
            rs.publish(exchange=LOG_EXCHANGE, routing_key=TASK_ROUTE_KEY, message=tr_body)
    else:
        task_rep["requestId"] = repo["infos"]["requestId"]
        tr_body = json.dumps(task_rep)
        rs.publish(exchange=LOG_EXCHANGE, routing_key=TASK_ROUTE_KEY, message=tr_body)

def rpc_query_common(func):

    def wrapper(method, properties, body):
        info("[x] Received %r" % (body))
        info("[x] Begin to do %s ..." % (method.routing_key))
        # publish message to vulcanus-iaas-log access successful
        rs = RabbitmqService()
        req = json.loads(body, object_hook=byteify)

        # convert the data to current format.
        cmop2_adapter = Cmop2ParametersAdapter()
        request_info = cmop2_adapter.input_adapt(req)

        repo = func(**request_info)
        repo["StatusCode"] = repo["Infos"]["StatusCode"]
        repo["Message"] = repo["Infos"]["Message"]
        repo["RequestId"] = repo["Infos"]["RequestId"]
        response_info = cmop2_adapter.output_adapt(repo)

        rs.publish(exchange='', routing_key=properties.reply_to,
                   properties=pika.BasicProperties(correlation_id=properties.correlation_id),
                   message=json.dumps(response_info))

        # publish message to vulcanus-iaas-log with task report
        task_report(body, response_info, "%s.result" % (method.routing_key))

    return wrapper

def rpc_process(ch, method, properties, body):

    # debug("Get rpc call body : %r" % (body))
    ALIYUN_RPC_CALLBACK_DICT = {
        describe_rds_attr: None,
        describe_rdses: None,
        describe_rds_net_info: None,
        describe_rds_white_ips: None,
        describe_rds_regions: None,
        describe_rds_ha_conf: None,
        describe_rds_ssl: None,
        describe_rds_tde: None
    }
    # report to log the rpc is began
    ch.basic_publish(exchange=LOG_EXCHANGE, routing_key="result.access.successful",
                     body="Accept rpc request successful!")

    if method.routing_key in ALIYUN_RPC_CALLBACK_DICT:
        evfunc = ALIYUN_RPC_CALLBACK_DICT[method.routing_key]
        evfunc(method, properties, body)
        # publish message to vulcanus-iaas-log execute complete
        ch.basic_publish(exchange=LOG_EXCHANGE, routing_key="result.access.successful",
                         body="Process %s request complete!" % (method.routing_key))
    else:
        msg = "There is no callback to process request %s." % (method.routing_key)
        ch.basic_publish(exchange=LOG_EXCHANGE, routing_key="result.access.failure",
                         body=msg)

    ch.basic_ack(delivery_tag=method.delivery_tag)

def event_process_common(func):
    def wrapper(method, properties, body):
        info("[x] Received %r" % (body))
        info("[x] Begin to do %s ..." % (method.routing_key))
        # publish message to vulcanus-iaas-log access successful
        rs = RabbitmqService()

        # get basic info
        req = json.loads(body, object_hook=byteify)

        # convert the data to current format.
        cmop2_adapter = Cmop2ParametersAdapter()
        request_info = cmop2_adapter.input_adapt(req)
        repo = {}
        try:
            repo = func(**request_info)
        except Exception as ex:
            repo["StatusCode"] = "Error"
            repo["Message"] = "Failed to execute %s with some exceptions %s." % \
                              (func.__name__, traceback.format_exc())
            repo["Infos"] = {}
            repo["RequestId"] = ""

        response_info = cmop2_adapter.output_adapt(repo)

        msg = json.dumps(response_info)

        # publish message to vulcanus-iaas-computer with execute result
        result_key = "%s.result" % (method.routing_key)
        rs.publish(exchange=COMPUTE_EXCHANGE, routing_key=result_key,
                   message=msg)

        # publish message to vulcanus-iaas-log with task report
        task_report(body, response_info, result_key)

    return wrapper

@event_process_common
def event_create_rds(ak, sk, region_id, **kwargs):

    repo = {}
    aliy_op = ALiYunRdsOperation(ak, sk, region_id)
    # do some parameters validate
    rs = RabbitmqService()

    ret = aliy_op.CreateDBInstance(**kwargs)
    repo = dict(kwargs, **ret)
    if ret["StatusCode"] == "200":

        # check the status of the rds when it's not pending.
        for i in range(600):
            qs_res = aliy_op.DescribeDBInstanceAttribute(DBInstanceId=ret["DBInstanceId"])
            if qs_res["Items"]["DBInstanceAttribute"][0]["DBInstanceStatus"] == "Running":
                repo['Infos'] = qs_res
                break
            else:
                info("Rds status %s." % (qs_res["Items"]["DBInstanceAttribute"][0]["DBInstanceStatus"]))
            rs.sleep(60)
        else:
            err_msg = "Wait for rds creating failed."
            error(err_msg)
            repo['Infos'] = {}
            repo["StatusCode"] = "403"
            repo["Message"] = err_msg

    return repo

@event_process_common
def event_create_ro_rds(ak, sk, region_id, **kwargs):

    repo = {}
    aliy_op = ALiYunRdsOperation(ak, sk, region_id)

    ret = aliy_op.CreateReadOnlyDBInstance(**kwargs)
    repo = dict(kwargs, **ret)
    return repo

@event_process_common
def event_create_db(ak, sk, region_id, **kwargs):

    repo = {}
    aliy_op = ALiYunRdsOperation(ak, sk, region_id)

    ret = aliy_op.CreateDatabase(**kwargs)
    repo = dict(kwargs, **ret)
    return repo

@event_process_common
def event_create_account(ak, sk, region_id, **kwargs):

    repo = {}
    aliy_op = ALiYunRdsOperation(ak, sk, region_id)

    ret = aliy_op.CreateAccount(**kwargs)
    repo = dict(kwargs, **ret)
    return repo

@event_process_common
def event_delete_rds(ak, sk, region_id, **kwargs):
    repo = {}
    aliy_op = ALiYunRdsOperation(ak, sk, region_id)

    ret = aliy_op.DeleteDBInstance(**kwargs)
    repo = dict(kwargs, **ret)
    return repo

@event_process_common
def event_delete_db(ak, sk, region_id, **kwargs):

    repo = {}
    aliy_op = ALiYunRdsOperation(ak, sk, region_id)

    ret = aliy_op.DeleteDatabase(**kwargs)
    repo = dict(kwargs, **ret)
    return repo

@event_process_common
def event_delete_account(ak, sk, region_id, **kwargs):

    repo = {}
    aliy_op = ALiYunRdsOperation(ak, sk, region_id)

    ret = aliy_op.DeleteAccount(**kwargs)
    repo = dict(kwargs, **ret)
    return repo

def _event_modify_common(op_func, update_keys, db_func=None, **kwargs):
    repo = {}
    kwargs_keys = set(kwargs.keys())
    k_update_keys = update_keys & kwargs_keys
    if k_update_keys:
        update_dict = {}
        for update_key in k_update_keys:
            update_dict[update_key] = kwargs[update_key]
        ret = op_func(**kwargs)
        if "Filters" not in kwargs:
            kwargs["Filters"] = {"DBInstanceId": kwargs["DBInstanceId"]}

        if db_func:
            db_func(update_dict=update_dict, **kwargs["Filters"])

        repo = dict(kwargs, **ret)

        if "Infos" not in repo:
            repo["Infos"] = {}

        for k, v in update_dict.items():
            nk = "%s%s" % (k[0].lower(), k[1:])
            repo["Infos"][nk] = v
    else:
        repo["StatusCode"] = "Error"
        repo["Message"] = "Failed to get any parameters to update (%s)." % (op_func.__name__)
        repo["Infos"] = {}
        repo["RequestId"] = ""
        repo = dict(repo, **kwargs)

    return repo

@event_process_common
def event_modify_db(ak, sk, region_id, **kwargs):
    aliy_op = ALiYunRdsOperation(ak, sk, region_id)
    update_keys = {"DBDescription", "DBName"}
    repo = _event_modify_common(aliy_op.ModifyDBDescription, update_keys,
                                None, **kwargs)
    return repo

@event_process_common
def event_modify_rds_pay_type(ak, sk, region_id, **kwargs):
    aliy_op = ALiYunRdsOperation(ak, sk, region_id)
    update_keys = {"PayType", "Period", "UsedTime"}
    repo = _event_modify_common(aliy_op.ModifyDBInstancePayType, update_keys,
                                None, **kwargs)
    return repo

@event_process_common
def event_modify_account_description(ak, sk, region_id, **kwargs):
    aliy_op = ALiYunRdsOperation(ak, sk, region_id)
    update_keys = {"AccountName", "AccountDescription"}
    repo = _event_modify_common(aliy_op.ModifyAccountDescription, update_keys,
                                None, **kwargs)
    return repo

@event_process_common
def event_modify_rds_auto_renew(ak, sk, region_id, **kwargs):
    # 实例自动续费
    aliy_op = ALiYunRdsOperation(ak, sk, region_id)
    update_keys = {"Duration", "AutoRenew"}
    repo = _event_modify_common(aliy_op.ModifyInstanceAutoRenewalAttribute, update_keys,
                                None, **kwargs)
    return repo

@event_process_common
def event_modify_rds_description(ak, sk, region_id, **kwargs):
    # 修改RDS实例备注
    aliy_op = ALiYunRdsOperation(ak, sk, region_id)
    update_keys = {"DBInstanceDescription"}
    repo = _event_modify_common(aliy_op.ModifyDBInstanceDescription, update_keys,
                                None, **kwargs)

    return repo

@event_process_common
def event_modify_rds_net_type(ak, sk, region_id, **kwargs):
    # 修改RDS实例网络类型
    aliy_op = ALiYunRdsOperation(ak, sk, region_id)
    update_keys = {"InstanceNetworkType", "VpcId", "VSwitchId", "PrivateIpAddress",
                   "ReadWriteSplittingPrivateIpAddres"}
    repo = _event_modify_common(aliy_op.ModifyDBInstanceNetworkType, update_keys,
                                None, **kwargs)
    return repo

@event_process_common
def event_modify_rds_connection_mode(ak, sk, region_id, **kwargs):
    # 修改RDS实例访问模式
    aliy_op = ALiYunRdsOperation(ak, sk, region_id)
    update_keys = {"ConnectionMode"}
    repo = _event_modify_common(aliy_op.ModifyDBInstanceConnectionMode, update_keys,
                                None, **kwargs)

    return repo

@event_process_common
def event_modify_rds_connection_string(ak, sk, region_id, **kwargs):
    # 修改连接串
    aliy_op = ALiYunRdsOperation(ak, sk, region_id)
    update_keys = {"CurrentConnectionString", "ConnectionStringPrefix", "Port"}
    repo = _event_modify_common(aliy_op.ModifyDBInstanceConnectionString, update_keys,
                                None, **kwargs)

    return repo

@event_process_common
def event_modify_rds_ha_config(ak, sk, region_id, **kwargs):
    # 修改RDS实例数据复制和高可用策略
    aliy_op = ALiYunRdsOperation(ak, sk, region_id)
    update_keys = {"SyncMode", "HAMode"}
    repo = _event_modify_common(aliy_op.ModifyDBInstanceHAConfig, update_keys,
                                None,**kwargs)

    return repo

@event_process_common
def event_modify_rds_maintain_time(ak, sk, region_id, **kwargs):
    # 修改RDS实例可维护时间
    aliy_op = ALiYunRdsOperation(ak, sk, region_id)
    update_keys = {"MaintainTime"}
    repo = _event_modify_common(aliy_op.ModifyDBInstanceMaintainTime, update_keys,
                                None, **kwargs)

    return repo

@event_process_common
def event_modify_rds_monitor(ak, sk, region_id, **kwargs):
    # 修改监控行为
    aliy_op = ALiYunRdsOperation(ak, sk, region_id)
    update_keys = {"Period"}
    repo = _event_modify_common(aliy_op.ModifyDBInstanceMonitor, update_keys,
                                None, **kwargs)

    return repo

@event_process_common
def event_modify_rds_white_ips(ak, sk, region_id, **kwargs):
    # 修改RDS实例IP白名单
    aliy_op = ALiYunRdsOperation(ak, sk, region_id)
    update_keys = {"SecurityIps", "DBInstanceIPArrayName", "DBInstanceIPArrayAttribute"}
    repo = _event_modify_common(aliy_op.ModifySecurityIps, update_keys,
                                None, **kwargs)
    return repo

@event_process_common
def event_modify_rds_ssl(ak, sk, region_id, **kwargs):
    # 修改实例SSL链路
    aliy_op = ALiYunRdsOperation(ak, sk, region_id)
    update_keys = {"ConnectionString"}
    repo = _event_modify_common(aliy_op.ModifyDBInstanceSSL, update_keys,
                                None, **kwargs)
    return repo

@event_process_common
def event_modify_rds_tde(ak, sk, region_id, **kwargs):
    # 修改实例数据加密状态
    aliy_op = ALiYunRdsOperation(ak, sk, region_id)
    update_keys = {"TDEStatus", "DBName"}
    repo = _event_modify_common(aliy_op.ModifyDBInstanceTDE, update_keys,
                                None, **kwargs)
    return repo

@event_process_common
def event_modify_rds_net_expire_time(ak, sk, region_id, **kwargs):
    # 修改连接地址过期时间
    aliy_op = ALiYunRdsOperation(ak, sk, region_id)
    update_keys = {"ConnectionString", "ClassicExpiredDays"}
    repo = _event_modify_common(aliy_op.ModifyDBInstanceNetworkExpireTime, update_keys,
                                None, **kwargs)
    return repo

@event_process_common
def event_modify_rds_spec(ak, sk, region_id, **kwargs):
    # 变更RDS实例规格
    aliy_op = ALiYunRdsOperation(ak, sk, region_id)
    update_keys = {"PayType", "DBInstanceClass", "DBInstanceStorage"}
    repo = _event_modify_common(aliy_op.ModifyDBInstanceSpec, update_keys,
                                None, **kwargs)
    # check the status of the rds when it's not pending.
    rs = RabbitmqService()
    for i in range(600):
        qs_res = aliy_op.DescribeDBInstanceAttribute(DBInstanceId=kwargs["DBInstanceId"])
        if qs_res["Items"]["DBInstanceAttribute"][0]["DBInstanceStatus"] == "Running":
            repo['Infos'] = qs_res
            break
        else:
            info("Rds status %s." % (qs_res["Items"]["DBInstanceAttribute"][0]["DBInstanceStatus"]))
        rs.sleep(60)
    else:
        err_msg = "Wait for rds modify spec failed."
        error(err_msg)
        repo['Infos'] = {}
        repo["StatusCode"] = "403"
        repo["Message"] = err_msg

    return repo

def _event_operation_common(op_func, **kwargs):
    repo = {}
    ret = op_func(**kwargs)
    repo = dict(kwargs, **ret)

    return repo

@event_process_common
def event_reset_account(ak, sk, region_id, **kwargs):
    aliy_op = ALiYunRdsOperation(ak, sk, region_id)
    repo = _event_operation_common(aliy_op.ResetAccount, **kwargs)
    return repo

@event_process_common
def event_reset_account_password(ak, sk, region_id, **kwargs):
    aliy_op = ALiYunRdsOperation(ak, sk, region_id)
    repo = _event_operation_common(aliy_op.ResetAccountPassword, **kwargs)
    return repo

@event_process_common
def event_power_restart_rds(ak, sk, region_id, **kwargs):
    aliy_op = ALiYunRdsOperation(ak, sk, region_id)
    repo = _event_operation_common(aliy_op.RestartDBInstance, **kwargs)
    # check the status of the rds when it's not pending.
    rs = RabbitmqService()
    for i in range(600):
        qs_res = aliy_op.DescribeDBInstanceAttribute(DBInstanceId=kwargs["DBInstanceId"])
        if qs_res["Items"]["DBInstanceAttribute"][0]["DBInstanceStatus"] == "Running":
            repo['Infos'] = qs_res
            break
        else:
            info("Rds status %s." % (qs_res["Items"]["DBInstanceAttribute"][0]["DBInstanceStatus"]))
        rs.sleep(60)
    else:
        err_msg = "Wait for rds restarting failed."
        error(err_msg)
        repo['Infos'] = {}
        repo["StatusCode"] = "403"
        repo["Message"] = err_msg
    return repo

@event_process_common
def event_allocate_rds_pub_conn(ak, sk, region_id, **kwargs):
    aliy_op = ALiYunRdsOperation(ak, sk, region_id)
    repo = _event_operation_common(aliy_op.AllocateInstancePublicConnection, **kwargs)
    # get public connect string information
    for i in range(1, 10):
        conn_str_info = aliy_op.DescribeDBInstanceNetInfo(DBInstanceId=kwargs["DBInstanceId"])
        if conn_str_info["StatusCode"] == "200":
            for conn_str in conn_str_info["DBInstanceNetInfos"]["DBInstanceNetInfo"]:
                if conn_str["IPType"] == "Public" and conn_str["ConnectionStringType"] == "Normal":
                    repo["Infos"] = conn_str
                    break
            else:
                repo["Infos"] = {}

            if repo["Infos"]:
                break
        time.sleep(6)
    else:
        repo["StatusCode"] = "403"
        repo["Message"] = "Failed to get public connection string."
    return repo

@event_process_common
def event_release_rds_pub_conn(ak, sk, region_id, **kwargs):
    aliy_op = ALiYunRdsOperation(ak, sk, region_id)
    repo = _event_operation_common(aliy_op.ReleaseInstancePublicConnection, **kwargs)
    return repo

@event_process_common
def event_switch_rds_net_type(ak, sk, region_id, **kwargs):
    aliy_op = ALiYunRdsOperation(ak, sk, region_id)
    repo = _event_operation_common(aliy_op.SwitchDBInstanceNetType, **kwargs)
    return repo

@event_process_common
def event_migrate_rds_to_oth_zone(ak, sk, region_id, **kwargs):
    aliy_op = ALiYunRdsOperation(ak, sk, region_id)
    repo = _event_operation_common(aliy_op.MigrateToOtherZone, **kwargs)
    return repo

@event_process_common
def event_purge_rds_log(ak, sk, region_id, **kwargs):
    aliy_op = ALiYunRdsOperation(ak, sk, region_id)
    repo = _event_operation_common(aliy_op.PurgeDBInstanceLog, **kwargs)
    return repo

@event_process_common
def event_upgrade_rds_engine_ver(ak, sk, region_id, **kwargs):
    aliy_op = ALiYunRdsOperation(ak, sk, region_id)
    repo = _event_operation_common(aliy_op.UpgradeDBInstanceEngineVersion, **kwargs)
    return repo

@event_process_common
def event_switch_rds_ha(ak, sk, region_id, **kwargs):
    aliy_op = ALiYunRdsOperation(ak, sk, region_id)
    repo = _event_operation_common(aliy_op.SwitchDBInstanceHA, **kwargs)
    return repo

def instance_event_process(ch, method, properties, body):

    ALIYUN_EVENT_CALLBACK_DICT = {
        create_rds: event_create_rds,
        delete_rds: event_delete_rds,
        restart_rds: event_power_restart_rds,
        modify_rds_spec: event_modify_rds_spec,
        modify_rds_pay_type: event_modify_rds_pay_type,
        modify_rds_auto_renew: event_modify_rds_auto_renew,
        allocate_rds_pub_conn: event_allocate_rds_pub_conn,
        release_rds_pub_conn: event_release_rds_pub_conn,
        switch_rds_net_type: event_switch_rds_net_type,
        modify_rds_conn_str: event_modify_rds_connection_string,
        modify_rds_conn_mode: event_modify_rds_connection_mode,
        modify_rds_net_type: event_modify_rds_net_type,
        modify_rds_white_ips: event_modify_rds_white_ips,
        migrate_rds_to_oth_zone: event_migrate_rds_to_oth_zone,
        purge_rds_log: event_purge_rds_log,
        upgrade_rds_engine_ver: event_upgrade_rds_engine_ver,
        modify_rds_description: event_modify_rds_description,
        modify_rds_maintain_time: event_modify_rds_maintain_time,
        modify_rds_ha_conf: event_modify_rds_ha_config,
        switch_rds_ha: event_switch_rds_ha,
        create_ro_rds: event_create_ro_rds,
        modify_rds_ssl: event_modify_rds_ssl,
        modify_rds_tde: event_modify_rds_tde,
        modify_rds_net_expire_time: event_modify_rds_net_expire_time,
        create_db: event_create_db,
        delete_db: event_delete_db,
        modify_db: event_modify_db,
        create_account: event_create_account,
        delete_account: event_delete_account,
        modify_account_description: event_modify_account_description,
        reset_account: event_reset_account,
        reset_account_password: event_reset_account_password
    }

    ch.basic_publish(exchange=LOG_EXCHANGE, routing_key="result.access.successful",
                     body="Accept %s request successful!" % (method.routing_key))

    if method.routing_key in ALIYUN_EVENT_CALLBACK_DICT:
        evfunc = ALIYUN_EVENT_CALLBACK_DICT[method.routing_key]
        evfunc(method, properties, body)
        # publish message to vulcanus-iaas-log execute complete
        ch.basic_publish(exchange=LOG_EXCHANGE, routing_key="result.access.successful",
                         body="Process %s request complete!" % (method.routing_key))
    else:
        msg = "There is no callback to process request %s." % (method.routing_key)
        ch.basic_publish(exchange=LOG_EXCHANGE, routing_key="result.access.failure",
                         body=msg)

    ch.basic_ack(delivery_tag=method.delivery_tag)

def start_rabbitmq_mode(args):
    # consumer event create.instance
    # publish event create.instance.log
    # publish event create.instance.stats
    host = args.rabbitmq_host
    port = args.rabbitmq_port
    user = args.rabbitmq_user
    password = args.rabbitmq_password
    rs = RabbitmqService(host, port, user, password)

    # create a channel, if one message can't be ack
    # the queue will be ignore
    rs.channel_create(prefetch_count=1)

    # # create a rpc server
    # rs.create_rpc_server(queue_name="Vulcanus.ecs.query", rpc_callback=rpc_process)

    # create two exchanges
    # declare exchange
    rs.exchange_declare(exchange=COMPUTE_EXCHANGE, type="topic", durable=True)
    rs.exchange_declare(exchange=LOG_EXCHANGE, type="fanout", durable=True)

    # bind queue
    # args = {"x-message-ttl": 60000}
    # related route keys
    route_keys = [ create_rds, delete_rds, restart_rds, modify_rds_pay_type, modify_rds_auto_renew,
                   allocate_rds_pub_conn, release_rds_pub_conn, switch_rds_net_type, modify_rds_spec,
                   modify_rds_conn_str, modify_rds_conn_mode, modify_rds_net_type, modify_rds_white_ips,
                   migrate_rds_to_oth_zone, purge_rds_log, upgrade_rds_engine_ver, modify_rds_description,
                   modify_rds_maintain_time, modify_rds_ha_conf, switch_rds_ha, create_ro_rds, modify_rds_ssl,
                   modify_rds_tde, modify_rds_net_expire_time, create_db, delete_db, modify_db,
                   create_account, delete_account, modify_account_description, reset_account_password,
                   reset_account ]

    q_name = "aliyun_rds_service"
    rs.queue_bind(COMPUTE_EXCHANGE, route_keys=route_keys,
                  queue_name=q_name, durable=True)
    rs.regist_consume(q_name, instance_event_process)

    # bind queue for rpc
    route_keys = [ describe_rds_attr, describe_rdses, describe_rds_net_info,
                   describe_rds_white_ips, describe_rds_regions, describe_rds_ha_conf,
                   describe_rds_ssl, describe_rds_tde ]
    q_name = "aliyun_rds_rpc"
    rs.queue_bind(COMPUTE_EXCHANGE, route_keys=route_keys,
                  queue_name=q_name, durable=True)
    rs.regist_consume(q_name, rpc_process)

    # start consuming
    rs.start_consuming()
    signal.signal(signal.SIGINT, _signal_handler)
    rs.consuming_loop()

def argument_parser():
    parser = argparse.ArgumentParser(description="Aliyun RDS Operation CLI.")

    # create actions subcommand
    sparsers = parser.add_subparsers(title="Actions", description="Actions of the service.",
                                     help="Action name, use -h after it for more details.")
    # start rabbitmq server
    sparser_rabbitmq_conn = sparsers.add_parser("start-rabbitmq-to-connect",
                                                help="Start as a worker service for API Server events exchange. Note: if you have multiple events to confim and public plse use config file.")
    sparser_rabbitmq_conn.set_defaults(func=start_rabbitmq_mode)

    sparser_rabbitmq_conn.add_argument("-H", "--host", action="store", type=str, dest="rabbitmq_host",
                                       help="Rabbitmq server host to connect.", required=False, default="localhost")
    sparser_rabbitmq_conn.add_argument("-p", "--port", action="store", type=int, dest="rabbitmq_port",
                                       help="Rabbitmq server port to connect.", required=False, default=5672)
    sparser_rabbitmq_conn.add_argument("-u", "--user", action="store", type=str, dest="rabbitmq_user",
                                       help="Rabbitmq server user to connect.", required=False, default="guest")
    sparser_rabbitmq_conn.add_argument("-P", "--password", action="store", type=str, dest="rabbitmq_password",
                                       help="Rabbitmq server password to connect.", required=False, default="guest")
    sparser_rabbitmq_conn.add_argument("-c", "--config", action="store", type=str, dest="conf_path",
                                       help="Server config file.", required=False, default=ALIYUN_SERVER_CONF)
    sparser_rabbitmq_conn.add_argument("-d", "--daemon", action="store", type=bool, dest="daemon",
                                       help="Server daemonized flag.", required=False, default=False)
    sparser_rabbitmq_conn.add_argument("-l", "--log-path", action="store", type=str, dest="log_path",
                                       help="Server log path.", required=False, default=ALIYUN_SERVER_LOG)

    return parser.parse_args()

if __name__ == "__main__":
    args = argument_parser()
    init(logpath=args.log_path)
    cd = ConfigureDiscovery()
    cmop2_adapter = Cmop2ParametersAdapter()
    cd.regist_observer("input_mapping", cmop2_adapter.input_notify)
    cd.regist_observer("output_mapping", cmop2_adapter.output_notify)
    # cd.regist_observer("db", aliyun_instance_db_model.notify)
    cd.start_observe_conf(conf_file=args.conf_path)
    cd.notify()
    args.func(args)
